import time
import traceback
from queue import Queue

from utils.stoppable_thread import StoppableThread


class ConsumerThread(StoppableThread):
    def __init__(self, queue_size=None, function=None, min_sleep_duration=0):
        super(ConsumerThread, self).__init__(daemon=True)
        self.queue = BufferQueue(queue_size)
        self.function = function
        self.min_sleep_duration = min_sleep_duration

        if self.function is None:
            raise ValueError("必须传入回调函数参数function")

    def join_queue(self, data):
        self.queue.put(data)

    def release(self):
        self.stop()
        self.queue.put(-1)

    def run(self):
        while True:
            try:
                m = self.queue.get()

                if self.is_stopped():
                    break

                start = time.time()

                self.function(m)

                if self.min_sleep_duration > 0:
                    sleep_duration = self.min_sleep_duration - (time.time() - start)
                    if sleep_duration > 0:
                        time.sleep(sleep_duration)
            except Exception as e:
                print("ConsumerThread: ", e)
                traceback.print_exc()

class BufferQueue(Queue):
    """Slight modification of the standard Queue that discards the oldest item
    when adding an item and the queue is full.
    稍稍修改标准队列的逻辑：
    当队列满的时候添加数据，先移除掉最老的数据
    """

    def put(self, item, *args, **kwargs):
        # The base implementation, for reference:
        # https://github.com/python/cpython/blob/2.7/Lib/Queue.py#L107
        # https://github.com/python/cpython/blob/3.8/Lib/queue.py#L121
        with self.mutex:
            if 0 < self.maxsize == self._qsize():
                self._get()
            self._put(item)
            self.unfinished_tasks += 1
            self.not_empty.notify()